#include "SPEngine.h"

//----------------------------------------------------------------------
// SPParticleSysyem
//-----------------------------------------------------------------------
namespace SP
{
	SPParticleSystem::SPParticleSystem( const WCHAR* path )
	{
		HANDLE hFile = CreateFile( path, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN,
			NULL );
		if( INVALID_HANDLE_VALUE == hFile )
			return;

		LARGE_INTEGER FileSize;
		GetFileSizeEx( hFile, &FileSize );
		UINT cBytes = FileSize.LowPart;

		BYTE* pBufPtr = new BYTE[cBytes];

		DWORD dwBytesRead;
		if( !ReadFile( hFile, pBufPtr, cBytes, &dwBytesRead, NULL ) )
			return;

		// close file
		CloseHandle( hFile );
		pBufPtr += sizeof( UINT );


		// compile
		BYTE* pBuf = pBufPtr;
		UINT* pNumEmitters = ( UINT* ) pBuf;
		pBuf += sizeof( UINT );
		// 
		for ( int i = 0; i < *pNumEmitters; i++ )
		{
			// Type
			UINT* pEmitterType = ( UINT* )pBuf;
			pBuf += sizeof( UINT );
			// EmitterBufferSize
			UINT* pEmitterBufferSize = ( UINT* )pBuf;
			pBuf += sizeof( UINT );

			SPEmitter* pNewEmitter = 0;
			switch( *pEmitterType )
			{
			case EMITTER_MESH:
				pNewEmitter = new SPEmitterMesh();
				break;
			case EMITTER_PARTICLE:
				pNewEmitter = new SPEmitterParticle();
				break;
			case EMITTER_BEAM:
				break;
			case EMITTER_ANIMTRAIL:
				break;
			}

			if ( pNewEmitter )
			{
				pNewEmitter->CreateFromFileBuffer( pBuf );
				m_EmitterList.push_back( pNewEmitter );
			}

			pBuf += *pEmitterBufferSize;
		}	
	}

	SPParticleSystem::SPParticleSystem( SPParticleSystem* archetype )
	{
		SPEmitterList::iterator it = archetype->m_EmitterList.begin();
		for ( ; it != archetype->m_EmitterList.end(); it++ )
		{
			SPEmitter* pNew = NULL;
			if ( SPEmitterParticle* p = dynamic_cast<SPEmitterParticle*>( *it ) )
			{
				pNew = new SPEmitterParticle( p );
			}

			if ( SPEmitterMesh* p = dynamic_cast<SPEmitterMesh*>( *it ) )
			{
				pNew = new SPEmitterMesh( p );
			}

			if ( pNew )
				m_EmitterList.push_back( pNew );
		}
	}

	SPParticleSystem::~SPParticleSystem()
	{
		SPEmitterList::iterator it = m_EmitterList.begin();
		for ( ; it != m_EmitterList.end(); it++ )
		{
			SAFE_DELETE( *it );
		}
	}
}


//----------------------------------------------------------------------
// SPObject
//-----------------------------------------------------------------------
namespace SP
{
	FLOAT SPObject::AngleBetweenVector( XMVECTOR vFrom, XMVECTOR vTo )
	{
		return XMVectorGetX( XMVector3AngleBetweenNormals( vFrom, vTo ) );
	}

	// Rotation( 1, 0, 0, 0 ) <-> Direction( 0, 0, 1 )
	XMVECTOR SPObject::Rot2Dir( XMVECTOR vRot )
	{
		XMVECTOR vStart = XMVectorSet( 0.0f, 0.0f, 1.0f, 0.0f );
		XMMATRIX mRot = XMMatrixRotationQuaternion( vRot );		
		return XMVector3Transform( vStart, mRot );
	}

	XMVECTOR SPObject::Dir2Rot( XMVECTOR vDir )
	{		
		XMVECTOR vFrom = XMVectorSet( 0.0f, 0.0f, 1.0f, 0.0f );
		if ( XMVector3Equal( vFrom, vDir ) )
			return  XMQuaternionIdentity();

		FLOAT w = AngleBetweenVector( vFrom, vDir );
		XMVECTOR vPart = XMVector3Cross( vFrom, vDir );

		return XMQuaternionRotationAxis( vPart, w );
	}

	void SPObject::GetAxes( XMVECTOR vIn, XMVECTOR& vX, XMVECTOR& vY, XMVECTOR& vZ )
	{
		XMVECTOR vUp = XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f );

		vZ = XMVector3Normalize( vIn );		
		vX = XMVector3Cross( vIn, vUp );
		vX = XMVector3Normalize( vX );	
		vY = XMVector3Cross( vIn, vX );
		vY = XMVector3Normalize( vY );
	}

	XMVECTOR SPObject::XOnly( XMVECTOR vIn )
	{
		return XMVectorSet( XMVectorGetX( vIn ), 0.0f, 0.0f, 0.0 );
	}
	XMVECTOR SPObject::YOnly( XMVECTOR vIn )
	{
		return XMVectorSet( 0.0f, XMVectorGetY( vIn ), 0.0f, 0.0 );
	}
	XMVECTOR SPObject::ZOnly( XMVECTOR vIn )
	{
		return XMVectorSet( 0.0f, 0.0f, XMVectorGetZ( vIn ), 0.0 );
	}

	XMVECTOR SPObject::WOnly( XMVECTOR vIn )
	{
		return XMVectorSet( 0.0f, 0.0f, 0.0, XMVectorGetW( vIn ) );
	}
}



//----------------------------------------------------------------------
// SPActor
//-----------------------------------------------------------------------
namespace SP
{
	SPWorld* SPActor::m_pWorld = NULL;

	SPActor::SPActor()
	{
		XMFLOAT3 vZero( 0.0f, 0.0f, 0.0f );

		m_vLocation = vZero;
		XMStoreFloat4( &m_vRotation, XMQuaternionIdentity() );
		m_vScale = XMFLOAT3( 1.0f, 1.0f, 1.0f );
		m_vVelocity = vZero;
		m_vAcceleration = vZero;
		m_vDirection = XMFLOAT3( 0.0f, 0.0f, 1.0f );

		m_pOwner = NULL;
		m_bFollowOwner = false;

		m_bBegined = false;
	}

	SPActor::~SPActor()
	{
		if ( m_pOwner )
			m_pOwner->RemoveChild( m_pOwner );
		for ( SPActorList::iterator it = m_ActorList.begin(); it != m_ActorList.end(); it++ )
			SAFE_DELETE( *it );
	}

	void SPActor::AddChild( SPActor* child )
	{
		child->m_pOwner = this;
		m_ActorList.push_back( child );
	}

	void SPActor::RemoveChild( SPActor* child )
	{
		m_ActorList.remove( child );
	}

	void SPActor::Advance( float fElapsedTime )
	{
		if ( !m_bBegined )
		{
			m_bBegined = true;
			PostBeginPlay();
		}
		OnAdvance( fElapsedTime );
		for ( SPActorList::iterator it = m_ActorList.begin(); it != m_ActorList.end(); it++ )
		{
			( *it )->Advance( fElapsedTime );
		}

		for ( SPEmitterList::iterator it = m_EmitterList.begin(); it != m_EmitterList.end(); it++ )
		{
			( *it )->Advance( fElapsedTime );
		}
	}

	void SPActor::RenderDepthDisableEmitter()
	{
		for ( SPEmitterList::iterator it = m_EmitterList.begin(); it != m_EmitterList.end(); it++ )
		{
			if ( !( *it )->IsDepthEnable() )
				( *it )->Render();
		}

		for ( SPActorList::iterator it = m_ActorList.begin(); it != m_ActorList.end(); it++ )
		{
			( *it )->RenderDepthDisableEmitter();
		}
	}

	void SPActor::RenderDepthEnableEmitter()
	{
		for ( SPEmitterList::iterator it = m_EmitterList.begin(); it != m_EmitterList.end(); it++ )
		{
			if ( ( *it )->IsDepthEnable() )
				( *it )->Render();
		}

		for ( SPActorList::iterator it = m_ActorList.begin(); it != m_ActorList.end(); it++ )
		{
			( *it )->RenderDepthEnableEmitter();
		}
	}

	XMMATRIX SPActor::ComputeTransformMatrix()
	{
		XMVECTOR vTranslation = XMLoadFloat3( &m_vLocation );
		XMVECTOR qRotation = XMLoadFloat4( &m_vRotation );
		XMVECTOR vScale = XMLoadFloat3( &m_vScale );

		XMMATRIX mTransform = XMMatrixTransformation(
				XMVectorZero(),
				XMQuaternionIdentity(),
				vScale,
				XMVectorZero(),
				qRotation,
				vTranslation
			);
		
		return mTransform;
	}

	void SPActor::PostBeginPlay()
	{

	}

	void SPActor::OnAdvance( float fElapsedTime )
	{
		UpdateLocation( fElapsedTime );
	}
	
	void SPActor::UpdateLocation( float fElapsedTime )
	{
		XMVECTOR pos = XMLoadFloat3( &m_vLocation );
		XMVECTOR velo =XMLoadFloat3( &m_vVelocity );
		XMVECTOR accel = XMLoadFloat3( &m_vAcceleration );

		velo += accel * fElapsedTime;
		pos += velo * fElapsedTime;

		XMStoreFloat4x4( &m_mTransform, ComputeTransformMatrix() );
	}

	void SPActor::SetRotation( XMVECTOR qRot )
	{
		XMStoreFloat4( &m_vRotation, qRot );
		XMVECTOR vDir = Rot2Dir( qRot );
		XMStoreFloat3( &m_vDirection, vDir );
	}

	void SPActor::Rotate( XMVECTOR qRotDelta )
	{
		XMVECTOR qRot = XMLoadFloat4( &m_vRotation );
		qRot = XMQuaternionMultiply( qRot, qRotDelta );
		SetRotation( qRot );
	}

	void SPActor::SetRotation( FLOAT Pitch, FLOAT Yaw, FLOAT Roll )
	{
		SetRotation( XMQuaternionRotationRollPitchYaw( Pitch, Yaw, Roll ) );
	}

	void SPActor::Rotate( FLOAT Pitch, FLOAT Yaw, FLOAT Roll )
	{
		Rotate( XMQuaternionRotationRollPitchYaw( Pitch, Yaw, Roll ) );
	}

	void SPActor::SetDirection( const XMFLOAT3& dir )
	{
		m_vDirection = dir;
		XMVECTOR vDir = XMLoadFloat3( &m_vDirection );
		XMStoreFloat4( &m_vRotation, Dir2Rot( vDir ) );
	}

	void SPActor::TransformEmitter( CXMMATRIX m )
	{
		for ( SPEmitterList::iterator it = m_EmitterList.begin(); it != m_EmitterList.end(); it++ )
		{
			( *it )->SetActorTransformMatrix( m );
		}
	}

	void SPActor::SpawnEmittters( SPParticleSystem* archetype )
	{
		SPEmitterList::iterator it = archetype->m_EmitterList.begin();
		for ( ; it != archetype->m_EmitterList.end(); it++ )
		{
			SpawnEmitter( *it );
		}
	}

	void SPActor::SpawnEmitter( SPEmitter* pArchetype )
	{
		SPEmitter* pNew = NULL;
		if ( SPEmitterParticle* p = dynamic_cast<SPEmitterParticle*>( pArchetype ) )
		{
			pNew = new SPEmitterParticle();
			static_cast<SPEmitterParticle*>(pNew)->Create( p );
		}

		if ( SPEmitterMesh* p = dynamic_cast<SPEmitterMesh*>( pArchetype ) )
		{
			pNew = new SPEmitterMesh();
			static_cast<SPEmitterMesh*>(pNew)->Create( p );
		}

		if ( pNew )
			m_EmitterList.push_back( pNew );
	}
}


//----------------------------------------------------------------------
// SPWorld
//-----------------------------------------------------------------------
namespace SP
{
	SPWorld::SPWorld()
	{
		m_gGame = NULL;
		m_pWorld = this;
	}

	SPWorld::~SPWorld()
	{
		SAFE_DELETE( m_gGame ); 
	}

	void SPWorld::LoadGame( SPGame* pGame )
	{
		if ( pGame )
		{
			SAFE_DELETE( m_gGame );
			m_gGame = pGame;
			AddChild( m_gGame );
		}
	}

	void SPWorld::OnFrameMove( float fElapsedTime )
	{
		Advance( fElapsedTime );
	}

	void SPWorld::OnFrameRender()
	{
		RenderDepthEnableEmitter();		
	
		RenderDepthDisableEmitter();
	}

}


//----------------------------------------------------------------------
// SPGame
//-----------------------------------------------------------------------
namespace SP
{
	SPGame::SPGame()
	{
		m_pMap = NULL;

		m_bStarted = false;
		m_bGameOver = false;
	}

	SPGame::~SPGame()
	{
		SAFE_DELETE( m_pMap );
	}

	void SPGame::PostBeginPlay()
	{
		m_pPlayerController = SpawnPlayer();
		AddChild( m_pPlayerController );
	}

	void SPGame::StartMatch()
	{
		m_bStarted = true;
		m_bGameOver = false;
	}

	void SPGame::EndMatch()
	{
		m_bStarted = false;
		m_bGameOver = true;
	}

	SPPlayerController* SPGame::SpawnPlayer()
	{
		return new SPPlayerController();
	}

	void SPGame::OnAdvance( float fElapsedTime )
	{
		
	}

	void SPGame::SetPlayer( SPPlayerController* pPlayer )
	{
		if ( m_pPlayerController )
		{
			RemoveChild( m_pPlayerController );
			SAFE_DELETE( m_pPlayerController );
		}
		if ( pPlayer )
		{
			m_pPlayerController = pPlayer;
			AddChild( m_pPlayerController );
		}
	}

	void SPGame::AddBot( SPController* pBot )
	{
		if ( pBot )
		{
			m_ControllerList.push_back( pBot );
			AddChild( pBot );
		}
	}

	void SPGame::RemoveBot( SPController* pBot )
	{
		m_ControllerList.remove( pBot );
		RemoveChild( pBot );
	}
}


//----------------------------------------------------------------------
// SPPawn
//-----------------------------------------------------------------------
namespace SP
{
	SPPawn::SPPawn( SPController* pController )
	{
		m_pController = pController;
		m_pController->m_pPawn = this;
	}

	SPPawn::~SPPawn()
	{

	}
		
}


//----------------------------------------------------------------------
// SPController
//-----------------------------------------------------------------------
namespace SP
{
	SPController::SPController()
	{

	}

	SPController::~SPController()
	{

	}

	void SPController::PostBeginPlay()
	{
		m_pPawn = SpawnPawn();
		AddChild( m_pPawn );
	}

	SPPawn* SPController::SpawnPawn()
	{
		return new SPPawn( this );
	}
}


//----------------------------------------------------------------------
// SPPlayerController
//-----------------------------------------------------------------------
namespace SP
{
	SPPlayerController::SPPlayerController()
	{

	}

	SPPlayerController::~SPPlayerController()
	{
		SAFE_DELETE( m_pPlayerCamera );
	}

	void SPPlayerController::PostBeginPlay()
	{
		SPController::PostBeginPlay();

		m_pPlayerCamera = SpawnPlayerCamera();
		m_pPlayerCamera->m_pOwnerController = this;
		AddChild( m_pPlayerCamera );
	}

	SPPawn* SPPlayerController::SpawnPawn()
	{
		return SPController::SpawnPawn();
	}

	SPPlayerCamera* SPPlayerController::SpawnPlayerCamera()
	{
		return new SPPlayerCamera( this );
	}

	void SPPlayerController::OnAdvance( float fElapsedTime )
	{

	}
}


//----------------------------------------------------------------------
// SPPlayerCamera
//-----------------------------------------------------------------------
namespace SP
{
	SPPlayerCamera::SPPlayerCamera( SPPlayerController* pOwnerController )
	{
		m_pOwnerController = pOwnerController;
		m_pSPCamera = SPGetCamera();
	}

	SPPlayerCamera::~SPPlayerCamera()
	{

	}

	void SPPlayerCamera::OnAdvance( float fElapsedTime )
	{
		m_vEye = m_pOwnerController->m_vLocation;
		m_vLookAt.x = m_pOwnerController->m_vLocation.x + m_pOwnerController->m_vDirection.x;
		m_vLookAt.y = m_pOwnerController->m_vLocation.y + m_pOwnerController->m_vDirection.y;
		m_vLookAt.z = m_pOwnerController->m_vLocation.z + m_pOwnerController->m_vDirection.z;
		m_vUp = XMFLOAT3( 0.0f, 1.0f, 0.0f );

		if ( m_pSPCamera )
			m_pSPCamera->SetCamera( m_vEye, m_vLookAt, m_vUp );
	}
}